package uk.ljmu.qudexapps.swfspreadsheet.utilities;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import uk.ljmu.metadata.staticschemas.StaticSkos;
import uk.ljmu.qudexapps.swfspreadsheet.domain.VocabularyElement;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
//import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
import com.hp.hpl.jena.util.FileManager;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;

public class RdfFunctions {
    private static Logger log = Logger.getLogger(RdfFunctions.class);
    /**
     * Metadata schemas URLs
     */
    //public static final String DC_Schema = "http://purl.org/dc/elements/1.1/";
    //public static final String DC_Schema = "http://dublincore.org/documents/dces/";
    //public static final String DC_Schema = "http://dublincore.org/2012/06/14/dcelements.rdf";
    public static final String DC_Schema = "http://ensembletest.ljmu/dc.rdf";
    public static final String DCTERMS_Schema = "http://dublincore.org/2008/01/14/dcterms.rdf";
    public static final String RDF_Schema = "http://www.w3.org/1999/02/22-rdf-syntax-ns";
    public static final String RELS_Schema = "http://www.fedora-commons.org/definitions/1/0/fedora-relsext-ontology.rdfs";
    public static final String GEO_Schema = "http://www.w3.org/2003/01/geo/wgs84_pos#";
    public static final String Qudex_Schema = "http://example.org/qudex/";
    public static final String DDI2_Schema = "http://example.org/ddi2/";
    public static final String Skos_Schema = "http://www.w3.org/2009/08/skos-reference/skos.rdf";
    
    /**
     * Instanciates a new empty RDF model
     * 
     * @return RDF model
     */
    public static Model createModel() {
	Model model = ModelFactory.createDefaultModel();

	return model;
    }

    /**
     * Creates a RDF model containing RDF statements from file
     * 
     * @param rdfFileName
     * @return RDF model
     */
    public static Model loadRdfFileIntoModel(String rdfFileName) {
	Model model = ModelFactory.createDefaultModel();

	InputStream in = FileManager.get().open(rdfFileName);
	if (in == null) {
	    throw new IllegalArgumentException("File: " + rdfFileName
		    + " not found.");
	}
	// Second argument is URI for relative URLs in the RDF file
	model.read(in, null);
	return model;
    }

    /**
     * Creates a RDF model containing RDF statements from string
     * 
     * @param rdfxmlContents
     * @return RDF model
     */
    public static Model loadRdfStringIntoModel(String rdfxmlContents,
	    String encoding) {
	Model model = ModelFactory.createDefaultModel();

	InputStream in;
	try {
	    in = new ByteArrayInputStream(rdfxmlContents.getBytes(encoding));

	    // if (in. == null)
	    // {
	    // throw new IllegalArgumentException(
	    // "Error while creating model from RDF string" );
	    // }
	    // Second argument is URI for relative URLs in the RDF file
	    model.read(in, null);
	} catch (UnsupportedEncodingException e) {
	    log.fatal(e.getMessage());
	    return null;
	}

	return model;
    }

   /* public static List<VocabularyElement> readPropertiesFromSchema(
	    String uriSchema) {
	List<VocabularyElement> elemlist = new ArrayList<VocabularyElement>();
	boolean errorConnect = false;
	Model model = ModelFactory.createDefaultModel();
	try {
	    model.read(uriSchema);
	} catch (Exception ex) {
	    System.out.println(ex.getMessage());
	    errorConnect = true;
	}

	if (errorConnect) {
	    return null;
	}
	ResIterator schemaProperties = model.listSubjectsWithProperty(RDF.type,
		RDF.Property);

	while (schemaProperties.hasNext()) {
	    Resource res = (Resource) schemaProperties.next();
	    try {
		VocabularyElement aux = new VocabularyElement();
		aux.setName(res.getLocalName());
		if (res.getProperty(RDFS.label) != null)
		    aux.setLabel(res.getProperty(RDFS.label).getString());
		else
		    aux.setLabel("");
		aux.setType(RDF.Property.getLocalName());
		if (res.getProperty(RDFS.comment) != null) {
		    String comment = res.getProperty(RDFS.comment).getString();
		    StmtIterator iterStatement = res
		    .listProperties(RDFS.comment);
		    while (iterStatement.hasNext()) {
			Statement statemnt = iterStatement.nextStatement();
			if (statemnt.getLanguage().equals("en")) {
			    comment = statemnt.getString();
			    break;
			}
		    }
		    aux.setComment(comment);
		}

		elemlist.add(aux);
	    } catch (Exception ex) {
		System.out.println(ex.getMessage());
	    }
	}
	return elemlist;
    }*/

    public static List<VocabularyElement> readPropertiesFromSchema(
	    Model auxModel) {
	List<VocabularyElement> elemlist = new ArrayList<VocabularyElement>();

	ResIterator schemaProperties = auxModel.listSubjectsWithProperty(
		RDF.type, RDF.Property);

	while (schemaProperties.hasNext()) {
	    Resource res = (Resource) schemaProperties.next();
	    try {
		VocabularyElement aux = new VocabularyElement();
		aux.setName(res.getLocalName());
		if (res.getProperty(RDFS.label) != null)
		    aux.setLabel(res.getProperty(RDFS.label).getString());
		else
		    aux.setLabel("");
		aux.setType(RDF.Property.getLocalName());
		Statement commentSt = res.getProperty(RDFS.comment);
		Statement definitionSt = res.getProperty(StaticSkos.definition);
		if (commentSt != null || definitionSt != null) {
		    String comment = commentSt != null ? commentSt.getString() :
			definitionSt.getString();
		    
		    if (commentSt != null) {
        		    StmtIterator iterStatement = res
        		    .listProperties(RDFS.comment);
        		    while (iterStatement.hasNext()) {
        			Statement statement = iterStatement.nextStatement();
        			if (statement.getLanguage().equals("en")) {
        			    comment = statement.getString();
        			    break;
        			}
        		    }
		    }
		    aux.setComment(comment);
		}
		//ALL HIDDEN BY DEFAULT
		aux.setHidden(true);
		elemlist.add(aux);
	    } catch (Exception ex) {
		System.out.println(ex.getMessage());
	    }
	}
	return elemlist;
    }

    public static void renderProperty(Resource channel, PrintStream out) {
	String label = null;
	String comment = null;

	label = channel.getProperty(RDFS.label).getString();
	comment = channel.getProperty(RDFS.comment).getString();

	System.out.println(label);
	System.out.println(comment);

    }
    /**
     * Returns a vocabulary element instance from a model if the element has been found
     * @param elementName element name to find in the metadata model
     * @param model RDF model of the metadata schema to use
     * @return vocabulary element from model if found, null otherwise
     */
    public static VocabularyElement getElementFromModel(String elementName,
	    Model model) {
	VocabularyElement resElement = new VocabularyElement();
	boolean enc = false;
	//Just in case the input model is null
	if (model == null)
	    return null;
	ResIterator schemaProperties = model.listSubjectsWithProperty(RDF.type,
		RDF.Property);

	while (schemaProperties.hasNext()) {
	    Resource res = (Resource) schemaProperties.next();
	    try {
		resElement = new VocabularyElement();
		if (res.getLocalName().equalsIgnoreCase(elementName)) {
		    resElement.setName(res.getLocalName());
		    if (res.getProperty(RDFS.label) != null)
			resElement.setLabel(res.getProperty(RDFS.label).getString());
		    else resElement.setLabel("");
		    resElement.setType(RDF.Property.getLocalName());
		    if (res.getProperty(RDFS.comment) != null) {
			String comment = res.getProperty(RDFS.comment).getString();
			StmtIterator iterStatement = res
			.listProperties(RDFS.comment);
			while (iterStatement.hasNext()) {
			    Statement statemnt = iterStatement.nextStatement();
			    if (statemnt.getLanguage().equals("en")) {
				comment = statemnt.getString();
				break;
			    }
			}
			resElement.setComment(comment);
			enc = true;
			break;
		    }
		}
	    } catch (Exception ex) {
		System.out.println(ex.getMessage());
	    }
	}
	if (enc)
	    return resElement;
	else return null;
    }
}
